package top.infopub.util;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * ftp操作工具类，使用的是apache.commons.net.ftp.FTPClient</br>
 * <B>ftp使用主动模式</B>
 * @author Awoke
 * @version 2018年5月13日
 * @see ApacheFtpUtils
 * @since
 */
public final class ApacheFtpUtils {

    private static Logger logger = LoggerFactory.getLogger(ApacheFtpUtils.class);

    /**
     * 上传到ftp服务器
     * @param file 本地文件
     * @param remotePath 服务器地址 不含文件名
     * @param remoteFileName 上传到ftp后的文件名
     * @param config ftpUserConfig
     * @see
     */
    public static boolean uploadFile(File localFile, String remotePath, String remoteFileName,
                                  FtpUser config) {
        if (!remotePath.endsWith("/")) {
            remotePath = remotePath + "/";
        }
        FTPClient ftp = connectFtp(config);
        if (ftp == null) {
            logger.error("uploadFile error~ remotePath={}, remoteFileName={} ", new Object[] {
                remotePath, remoteFileName});
            return false;
        }
        FileInputStream input = null;
        try {
            // 创建ftp文件夹
            ftp.makeDirectory(remotePath);
            input = new FileInputStream(localFile);
            if (ftp.storeFile(remotePath + remoteFileName, input)) {
                logger.info("uploadFile successfully~ remotePath={}, remoteFileName={} ",
                    new Object[] {remotePath, remoteFileName});
                return true;
            }
            else {
                logger.error("uploadFile failed~ remotePath={}, remoteFileName={} ", new Object[] {
                    remotePath, remoteFileName});
                return false;
            }
        }
        catch (Exception e) {
            logger.error("uploadFile error~ remotePath={}, remoteFileName={}", new Object[] {
                remotePath, remoteFileName});
            logger.error("", e);
            return false;
        }
        finally {
            IOUtils.closeQuietly(input);
            closeFtp(ftp);
        }
    }

    /** 
     * 从ftp服务器下载文件夹
     * @param localBaseDir 本地文件夹
     * @param remoteBaseDir 本地文件夹
     * @param config ftpUserConfig
     */
    public static int batchDownLoadFile(String localBaseDir, String remoteBaseDir, FtpUser config) {
        // 成功下载文件数目
        int downloadSuccessCount = 0;

        if (!localBaseDir.endsWith("/")) {
            localBaseDir = localBaseDir + "/";
        }
        if (!remoteBaseDir.endsWith("/")) {
            remoteBaseDir = remoteBaseDir + "/";
        }
        FTPClient ftp = connectFtp(config);
        if (ftp == null) {
            logger.error("batchDownLoadFile error~ localBaseDir={}, remoteBaseDir={} ",
                new Object[] {localBaseDir, remoteBaseDir});
            return 0;
        }
        // 创建本地文件夹
        createDir(localBaseDir);
        try {
            FTPFile[] files = null;
            boolean changedir = ftp.changeWorkingDirectory(remoteBaseDir);
            if (changedir) {
                // 由于apache不支持中文语言环境，通过定制类解析中文日期类型  
                ftp.configure(new FTPClientConfig(
                    "com.zznode.tnms.ra.c11n.nj.resource.ftp.UnixFTPEntryParser"));
                FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
                conf.setServerLanguageCode("zh");

                files = ftp.listFiles();
                for (int i = 0; i < files.length; i++ ) {
                    try {
                        // 下载文件
                        downloadFile(ftp, files[i], localBaseDir);
                        downloadSuccessCount++ ;
                    }
                    catch (Exception e) {
                        logger.error("", e);
                        logger.error("<" + files[i].getName() + "下载失败");
                    }
                }
            }
        }
        catch (Exception e) {
            logger.error("batchDownLoadFile error~ localBaseDir={}, remoteBaseDir={} ",
                new Object[] {localBaseDir, remoteBaseDir});
            logger.error("", e);
        }
        finally {
            closeFtp(ftp);
        }
        return downloadSuccessCount;
    }

    /**
     * 下载FTP文件  
     * @param ftp FTPClient
     * @param ftpFile ftpFile
     * @param localBaseDir 本地文件夹
     * @throws Exception 
     * @see
     */
    private static void downloadFile(FTPClient ftp, FTPFile ftpFile, String localBaseDir)
        throws Exception {
        String filename = ftpFile.getName();
        OutputStream outputStream = null;
        try {
            File locaFile = new File(localBaseDir + filename);
            // 若文件已存在则返回  
            if (locaFile.exists()) {
                logger.info("目标文件{} 已存在", locaFile.getPath());
                return;
            }
            else {
                outputStream = new FileOutputStream(localBaseDir + filename);
                ftp.retrieveFile(ftpFile.getName(), outputStream);
                outputStream.flush();
                logger.info("目标文件{} 下载成功", locaFile.getPath());
            }
        }
        catch (Exception e) {
            logger.error("", e);
        }
        finally {
            IOUtils.closeQuietly(outputStream);
        }

    }

    /** 
     * 获取FTPClient
     * @param config 
     * @return 
     */
    private static FTPClient connectFtp(FtpUser config) {
        try {
            FTPClient ftp = new FTPClient();
            int reply;
            ftp.connect(config.getIp(), Integer.valueOf(config.getPort()));
            ftp.login(config.getUserName(), config.getPassword());
            // 主动模式
            ftp.enterRemoteActiveMode(InetAddress.getByName(config.getIp()),
                Integer.valueOf(config.getPort()));
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                logger.info("获取FTPClient链接失败~");
                ftp.disconnect();
                return null;
            }
            return ftp;
        }
        catch (Exception e) {
            logger.error("获取FTPClient链接异常", e);
            return null;
        }
    }

    /** 
     * 关闭FTP连接 
     */
    private static void closeFtp(FTPClient ftp) {
        if (ftp != null && ftp.isConnected()) {
            try {
                ftp.logout();
                ftp.disconnect();
            }
            catch (IOException e) {
                logger.error("", e);
            }
        }
    }

    /**
     * 创建目录
     * @param destDirName 目录名
     * @return
     */
    private static void createDir(String destDirName) {
        File dir = new File(destDirName);
        if (!dir.exists()) {
            // 创建目录  
            if (dir.mkdirs()) {
                logger.info("创建目录 {}成功", destDirName);
            }
            else {
                logger.info("创建目录 {}失败", destDirName);
            }
        }
    }

    /**
     * Test
     * @param args
     * @throws Exception 
     * @see
     */
    public static void main(String[] args)
        throws Exception {
        FtpUser f = new FtpUser();
        String serverUrl = "192.168.0.13";
        String userName = "admin";
        String passWord = "admin";
        String port = "21";
        // ip地址  
        f.setIp(serverUrl);
        // ftp用户名  
        f.setUserName(userName);
        // ftp密码  
        f.setPassword(passWord);
        // 端口号  
        f.setPort(port);

        ApacheFtpUtils.uploadFile(new File("D:\\id-card\\awoke-test.txt", "UTF-8"), "jscl",
            "awoke-test.txt", f);

        String local = "D:/id-card/jscl";
        String remote = "/home/admin/jscl";
        ApacheFtpUtils.batchDownLoadFile(local, remote, f);
    }

}